// Initialize widget
window.OSV          = window.OSV || {};
OSV.widgetAddr      = 'http://widgets.opera.com/widget/15172/';
OSV.gal             = $('#thumbsPane');
OSV.allpics         = [];
OSV.folderTree      = [];
OSV.fixedFiles      = [];
OSV.mountPoints     = {};
OSV.currentMP       = null;
OSV.OFS             = opera.io.filesystem;
OSV.currentFile     = {file: null, ZoomNPan: null};
OSV.thumbSize       = pref('thumbSize') || 64;
OSV.SVGAsImg        = $.browser.version >= 11.10; // I know it's lame but to test properly a user selected mountpoint is required
OSV.SVGSamplesPath  = 'SVG samples';
OSV.SVGNS           = 'http://www.w3.org/2000/svg';
OSV.ppp             = pref('ppp') || 20; // Pictures per page
//OSV.includeBitmap   = pref('includeBitmap') || 'false'; //needs to be a string
openLastDir         = pref('openLastDir') || 'true'; //needs to be a string
sidebarWestInitClosed = (pref('sidebarWestInitClosed') === 'true' || pref('sidebarWestInitClosed') === '') || false;
$(document).ready(function(){
    OSV.makeLayout();
    OSV.attachHotkeys();
	OSV.setThumbsSize(OSV.thumbSize);
    // Set checkboxes & such
	if (pref('fitViewport') === 'true') $('.cmd-fit-viewport.menuitem-checkbox').addClass('selected-checkbox');
	if (pref('fitBig') === 'true' || !pref('fitBig')) OSV.toggleFitBig(true);// set true on 1st run
	if (pref('trGrid') === 'true') OSV.toggleTransparencyGrid(true);
    if (pref('wireframeOn') === 'true') $('.cmd-toggle-wireframe.menuitem-checkbox').addClass('selected-checkbox');
    if (pref('includeBitmap') === "true") $('.cmd-show-bitmap.menuitem-checkbox').addClass('selected-checkbox');
    $('input#qty').val(OSV.ppp);
	$('.cmd-delFile, .cmd-fixCurFile').addClass('disabled');

    // Event listeners
    $('input#qty').bind('change keyup', function(e){
        if (e.which && e.which !== 13) return;// 13 = Enter
        setPref($(this).val(), 'ppp');
        OSV.ppp = pref('ppp');
        showPage();
		$('#qty').blur();
    });
	
    $('#debugger').keyup(function(event){
        if (event.which == 13) {
			d(eval(this.value), this.value, 2)
        }
    });
	
	$('#pixPerPage').click(function(e){
		setPref($(this).attr('value'), 'ppp');
		setStatus($(this).attr('value')	);
		//$(this).parent().parent()
		OSV.ppp = pref('ppp');
		showPage();
	});
    
    $('.cmd-show-bitmap').click(function(e){OSV.toggleShowBitmap()});
	$('.cmd-toggle-grid').click(OSV.toggleTransparencyGrid);
	$('.cmd-fixCurFile') .click(function(e){fixFile(OSV.currentFile.file)});
	$('.cmd-fixFiles')   .click(function(e){ fixFiles(OSV.currentMP)});
	$('.cmd-delFile')    .click(function(e){
		if (!OSV.currentFile.file) return;
		modalConfirm({
			msg:'Delete the file from disk? <br/>  ',
			callback: function(){deleteFile(OSV.currentFile.file)},
			events: function(){	},
			silentID: 'dlg-delFile'
		})
	});
    /*$('.cmd-settings').click(function(e){ $('#prefsPage').modal({persist:true,escClose:true,overlayClose:true})});*/
    $('.cmd-openFolder').click(function(e){ OSV.addMountPoint()});	// Don't change!
	$('.cmd-toggle-zoomnpan').click(function(e){ OSV.toggleZoomNPan()});
    $(".cmd-fit-viewport").click(function(e){   OSV.toggleFitViewport()});
    $(".cmd-fit-big").click(function(e){ OSV.toggleFitBig()});
	$('.cmd-zoom-in').click(function(e){ OSV.zoomIn()});
	$('.cmd-zoom-out').click(function(e){ OSV.zoomOut()});
	$('.cmd-reset-zoom').click(function(e){ OSV.zoom1x()});
    $(".cmd-toggle-wireframe").click(function(e){ OSV.toggleWireframeMode()});
	$('.cmd-about').click(function(e){ $.modal(OSV.widgetInfo(), {escClose:true, overlayClose:true})});
	$('.cmd-show-hotkeys-list').click(function(e){$('#hotkeysList').modal({escClose:true, overlayClose:true})});
    $('#thumbsPane .innerScroller').click(OSV.resetCurFile);
	$('#thumbsPane').delegate('.thumb', 'click', selectFile );
	$('#menu').delegate('a[href]', 'click', function(evt){evt.stopPropagation();$(this).trigger('mouseleave')});
	$('.setThumbs').click( function(evt){OSV.setThumbsSize( $(this).attr('data-size'))});

    // Configure menu
	$('#menu').superfish({
		delay:       200,              // one second delay on mouseout
		animation:   {height:'show'},  // fade-in and slide-down animation
		speed:       0,                // faster animation speed
		autoArrows:  true,             // disable generation of arrow mark-up
		dropShadows: false,            // disable drop shadows
		disableHI:   true
	});
    // Configure behaviours of folder tree
    setTimeout(OSV.initTree(), 0);
    // Configure default modal dialogues
	$.extend($.modal.defaults, {
		closeHTML: ""
	   ,opacity: 100
	   ,onOpen: function (dialog) {
			OSV.detachHotkeys();
			dialog.overlay.fadeIn(200, function(){
				dialog.container.show();
				dialog.data.show();
			})
		}
	   ,onClose: function (dialog) {
			dialog.container.hide(1,function(){
				dialog.data.hide();
				dialog.overlay.fadeOut(300, function(){
					$.modal.close();
				});
			});
			OSV.attachHotkeys()
		}
		,escClose: false
		,focus: false
	});
	//Fix widget not receiving keyboard events upon load
	$(window).focus();
	$(window).blur(function(e){$(window).focus()});

});
// END INIT
OSV.hotkeys = {
    keypress : {
        '+':			function(evt){ evt.preventDefault(); OSV.zoomIn()  },
        '-':			function(evt){ evt.preventDefault(); OSV.zoomOut() },
        ']':			function(evt){ evt.preventDefault(); OSV.zoomIn()  },
        '[':			function(evt){ evt.preventDefault(); OSV.zoomOut() }
    },
    keyup : {
        '0':			function(evt){ OSV.zoom1x() },
        'Esc':			function(evt){ OSV.toggleZoomNPan() },
        //'Tab':			function(evt){ evt.preventDefault(); $('#pager .next').click() },
        'PageDown':		function(evt){ evt.preventDefault(); $('#pager .next').click() },
        //'Shift+Tab':	function(evt){ evt.preventDefault(); $('#pager .prev').click() },
        'PageUp':		function(evt){ evt.preventDefault(); $('#pager .prev').click() },
        'Home':			function(evt){ evt.preventDefault(); $('#pager .prev + a').click() },
        'End':			function(evt){ evt.preventDefault(); $('#pager .next').prev().click() },
        'Space':		function(evt){ OSV.focusNextThumb() },
        'Backspace':	function(evt){ OSV.focusPrevThumb() },
        'right':		function(evt){ OSV.focusNextThumb() },
        'left':			function(evt){ OSV.focusPrevThumb() },
        'up':			function(evt){ OSV.focusUpThumb() },
        'down':			function(evt){ OSV.focusDownThumb() },
        'Ctrl+o':		function(evt){ OSV.addMountPoint() },
        'w':	    	function(evt){ OSV.toggleWireframeMode() },
        'g':		    function(evt){ OSV.toggleTransparencyGrid() },
        'z':		    function(evt){ OSV.currentFile.ZoomNPan.animateZoom1x() },
        
        'Ctrl+m':		function(evt){ dumpMPs() },
        'Ctrl+d':		function(evt){ $('body').toggleClass('debug'); $('.debug #debugger').focus()},
        'm':			function(evt){ modalConfirm({}) }
    }
};
OSV.makeLayout = function (){
    OSV.outerLayout = $('#gallery').layout({
        west__paneSelector: '#folders',
        east__paneSelector: '#thumbsPane',
        center__paneSelector: '#singlePic',
        west__size: pref('outerWestSize') || 150,
        east__size: pref('outerEastSize') || 400,

        west__onresize_end: function (paneName, jqEl, state, opts, layNm){setPref(state.size, 'outerWestSize')},
        east__onresize_end: function (paneName, jqEl, state, opts, layNm){setPref(state.size, 'outerEastSize')},
        center__onresize_end: function() {
            if (OSV.currentFile.ZoomNPan){
                OSV.currentFile.ZoomNPan.makeViewBox( pref('fitViewport') ==='true', pref('fitBig') ==='true', true );
                //OSV.showCurZoom()
            }
        },

        west__onclose_end: function() {setPref('true', 'outerWestInitClosed')},
        east__onclose_end: function() {setPref('true', 'outerEastInitClosed')},

        west__onopen_end: function() {setPref('false', 'outerWestInitClosed')},
        east__onopen_end: function() {setPref('false', 'outerEastInitClosed')},

/*      onresize_start: function(paneName, jqEl, state, opts, layNm){},
        onresize_end: function(paneName, jqEl, state, opts, layNm){},*/

        //initClosed: outerWestInitClosed,
        west__initClosed: pref('outerWestInitClosed') === 'true',
        east__initClosed: pref('outerEastInitClosed') === 'true',
        center__onresize: "sidebarLayout.resizeAll"
    });
};

OSV.attachHotkeys = function() {
	for (var evt in OSV.hotkeys){
		if (OSV.hotkeys.hasOwnProperty(evt)) {
			for (var key in OSV.hotkeys[evt]){
				if (OSV.hotkeys[evt].hasOwnProperty(key)) {
					$(document).bind(evt, key, OSV.hotkeys[evt][key]);
				}
			}
		}
	}
};
OSV.detachHotkeys = function() {
	for (var evt in OSV.hotkeys){
		if (OSV.hotkeys.hasOwnProperty(evt)) {
			for (var key in OSV.hotkeys[evt]){
				if (OSV.hotkeys[evt].hasOwnProperty(key)) {
					$(document).unbind(evt, OSV.hotkeys[evt][key]);
				}
			}
		}
	}
};
OSV.initTree = function(){
    $('#recentDirs')
    .bind("loaded.jstree", function (event, data) {
            if(typeof pref('lastOpenPath') == 'undefined'){
                data.inst.select_node($('#recentDirs>ul>li:first-child'))
            }
    })
    .jstree({
        core: {
            load_open:true,
            animation: 300
        },
        "themes": {
            "theme": "default",
            "dots": true,
            "icons": true
        },
        "ui": {
            "select_limit": 1,
            "initially_select": (function(){
                var target = OSV.getLastDir(pref('lastOpenPath'));
                if(target) {
					return [toid(target.path)]
				}
				else{
					// dumb method to select SVG samples dir
					return [toid('mountpoint://application/'+ encodeURIComponent( OSV.SVGSamplesPath ))]
				}
            })()
        },
        "plugins": [ "themes", "json_data", "ui"],
        "json_data": {
            correct_state: true,
            data: function(node, fn){
                fn (node === -1
                    ? OSV.makeInitJSTreeJSON()
                    : node[0] && OSV.getDirByPath(node[0].dataset.path)
						&& OSV.getFolderChildren(OSV.getDirByPath(node[0].dataset.path))
               );
            }
        }
    })
    .bind('open_node.jstree', function(evt, data){
        //setStatus('open_node.jstree')
    })
    .bind('create_node.jstree', function(evt, data){
        data.inst.select_node(data.rslt.obj);
    })
    .bind('load_node.jstree', function(evt, data){
        if(data.rslt.obj === -1) return;
    })
    .bind("select_node.jstree", function(evt, data) {
        OSV.gal.find('.innerScroller').addClass('loading');
        OSV.resetCurFiles();
        var li = data.rslt.obj;
        if (!li.hasClass('jstree-isloaded')){
            li.find('>a').addClass('jstree-loading');
            data.inst.load_node(li, function(e){
                li.find('>a').removeClass('jstree-loading');
                data.inst.open_node(li);
            },
            function(evt, data){});
            li.addClass('jstree-isloaded');
        }
        else if ( li.hasClass('jstree-isloaded' && li.has('>a.jstree-clicked'))){
                data.inst.toggle_node(li); return false
        }
        else{
            data.inst.open_node(li);
        }
        setStatus(li.attr('class'));
        OSV.scanFolder(OSV.getDirByPath(li[0].dataset.path));
    });
/*    .delegate("a", "click", function (e) {
        e.stopImmediatePropagation();
        if($(this).hasClass('jstree-clicked')){
            $('#recentDirs').jstree('close_node', $(this).closest('li'))
        }
            
    })*/
};

/*
*
* */
OSV.makeInitJSTreeJSON = function(){
    var items = [];
    var mps = OSV.OFS.mountPoints;
    if(!mps.length){
        mps = [];
        mps.push(OSV.OFS.mountSystemDirectory('application').resolve(OSV.SVGSamplesPath))
    }
	$.each(mps, function(index, dir) {
        if(dir.exists && dir.isDirectory && (!dir.isHidden || dir.nativePath.length === 3 )){
            // dir.nativePath.length === 3 : fix for root folders like D:/ always hidden
            var item = OSV.makeFolderJSON(dir);
            var curPath = fromid(item.attr.id);
            var target = pref('lastOpenPath');
            // if it's a parent folder of the last opened folder get children
            if(target.indexOf(curPath+"/") === 0){
                item.children = OSV.getFolderChildren(dir, target);
                item.state = 'open';
                item.attr.className = 'jstree-isloaded'
            }
            items.push(item)
        }
	});
    if (items.length) return items
};
/**
*	Retrieve the last directory suitable for loading
*   @param dir File object
**/
OSV.getLastDir = function (dir) {
    if (dir && typeof dir === 'string'){
        dir = OSV.getDirByPath(dir)
    }
    if (dir && !dir.exists){
        // get parent if the dir doesn't exist
        var parents = dir.path.substring(13).split('/');
        if (parents.length > 0){
            parents.length -= 1;
            dir = OSV.getDirByPath('mountpoint://'+ parents.join('/'));
            if (dir && !dir.exists) {dir = OSV.getLastDir(dir)}
            else if(!dir){return null}
            else{setPref(dir.path,'lastOpenPath')}
        }
    }
	return dir
};

OSV.getDirByPath = function(path){
    if(!path){d('Cannot get dir by path: no path specified'); return}
    path = path.substring(13);
    var parents = path.split('/');
    var subpath = parents.slice(1).join('/');
    var mp = OSV.getMPByName(parents[0]);
    if (mp){ return mp.resolve(subpath)}
    else { d('Cannot get mountpoint '+parents[0])}
};

OSV.makeFolderJSON = function(file){
    if (!file) return;
    var folder = {
        data: OSV.getFolderName(file),
        attr: {
            "title": file.nativePath,
            "data-path": file.path,
            "id": toid(file.path)
        }
    };
    return folder
};
/**
 * Returns folder name
 * @param folder string or File object
 */
OSV.getFolderName = function(folder){
    var path = folder.nativePath || decodeURI(folder.path);
    if (path === '') {return OSV.SVGSamplesPath}
    var ret = '';

    var dirName = /[^\/\\]*$/.exec(path);
    if (dirName && (typeof dirName[0] === 'string')){
        ret = dirName[0];
        // if this is root eg D://
        if(dirName[0] === ''){ ret = path }
    }
    return ret
};
OSV.getFolderChildren = function (file, toPath){
    var kids = [];
    file.refresh();
    $.each(file, (function(index, subfile ){
        if (subfile.isDirectory && !subfile.isHidden ){
            var json = OSV.makeFolderJSON(subfile);
            if(toPath && toPath.indexOf(subfile.path+"/") === 0){
                if (!json.children) json.children = [];
                json.children.push(OSV.getFolderChildren(subfile, toPath));
                json.state = 'open';
            }
            kids.push(json);
        }
    }));
    return kids
};

OSV.getMPByName = function(name) {
	// if the last dir was the dir with SVG samples
	if (name == 'application') {
		return OSV.OFS.mountSystemDirectory ('application');
	}
	var mps = jQuery.grep(OSV.OFS.mountPoints, function (n, i){return n.name == name});
	if (mps.length)	return mps[0]
};


OSV.addMountPoint = function (){
    OSV.OFS.browseForDirectory(new Date().getTime(), 'Pictures', function(dir){
        if (!dir) {
            setStatus('No directory selected or can&apos;t access directory');
            return;
        }
        else {
            $('#recentDirs .jstree-clicked').removeClass('jstree-clicked');
            $('#recentDirs').jstree('create_node', -1, 'last', OSV.makeFolderJSON(dir));
        }
    }, true); //MP name, default location, callback, persistent
};

function removeMountPoint(dir){
    mp = jQuery.grep(OSV.OFS.mountPoints, function (n, i){
            if (n.name == dir) return true
            else return false
        });
    if (mp.length){
        dir = mp[0]
    }
	$('#mp_'+ dir ).remove();
	setStatus(dir +' removed');
	if( OSV.OFS.mountPoints.length ) {
		OSV.OFS.removeMountPoint(''+OSV.mountPoints[dir]);
		delete OSV.mountPoints[dir];
	}
}
OSV.scanFolder = function(dir){
    if (!dir){
        setStatus('Directory "'+ decodeURIComponent(arguments[0]) +'" does not exist');
        //notify('Directory "'+ decodeURIComponent(dir.nativePath) +'" does not exist');
        opera.postError( 'Directory "'+ decodeURIComponent(dir.nativePath) +'" does not exist');
        return
    }
    OSV.resetCurFiles(dir.nativePath);
    setPref(dir.path, 'lastOpenPath');

    OSV.currentMP = dir;
    var $pane = OSV.gal.find('.innerScroller');
    OSV.resetCurFile();
    $pane.addClass('loading');
    dir.refresh();
    // Collect files and folders into arrays
    for (var i = 0, file, picNo = -1; file = dir[i]; i++) {
        // Collect files
        if ( isPicture(file.path) ){
            picNo++;
            OSV.allpics[picNo] = file;
            OSV.allpics[picNo].html = makePicHTML(file);
        }
    }
    $pane.removeClass('loading');
    if (OSV.allpics.length == 0) {
        $pane.addClass('dirEmpty');
    }
    else if (OSV.allpics.length > 0) {
        showPage(0);
    }
};
/*
 *  Processes a page of images
 */
function showPage(pageN){
    var pageNo = pageN || 0;
    var pager = $('#pager');
    var total = OSV.allpics.length;
    if (total > OSV.ppp) {
        // First Parameter: number of items
        // Second Parameter: options object		
        pager.pagination(total, {
            items_per_page: OSV.ppp,
            callback: processPage,
            num_display_entries: 8,
            num_edge_entries: 1
        });
    }
    else {
        processPage(pageNo, pager);
    }
    
    // Show thumbs and other stuff
    function processPage(pageNo, pager){
        var out = '';
        var maxElem = Math.min(((pageNo + 1) * OSV.ppp), total);
        for (var i = pageNo * OSV.ppp; i < maxElem; i++) {
			out += OSV.allpics[i].html;
		}
		$('#thumbsPane .innerScroller').html(out).animate({scrollTop: 0}, 0);

        // Show total and current files in status bar
        if (total) {
            var cur = '';
            var from = ((pageNo + 1) * OSV.ppp) - OSV.ppp + 1; // Number of first current image
            if (from === maxElem) {cur = from }
            else {cur = from + '-' + maxElem }
            setStatus(cur + ' / ' + total, 'c-t');
        }
        return false;
    }
}


/**
 *	Hides all signs of currently displayed files
 *
 */
OSV.resetCurFiles = function(widgetTitle){
    setWidgetTitle(widgetTitle);
    OSV.gal.find('.innerScroller').removeClass('dirEmpty');
    $('#statusBar > *, #pager, #curZoom').html('');
    $('#thumbsPane figure').remove();
    OSV.allpics = []; // Reset array
    OSV.currentFile.file = null;// ??? needed?
	OSV.currentFile.ZoomNPan = null;
};


/**
*	Unselects selected thumbs
*/

OSV.resetCurFile = function(e) {
    if (e && !$(e.target).hasClass('innerScroller')) return;
    OSV.currentMP && setWidgetTitle(OSV.currentMP.nativePath);
    $('#bigPic').html('<span/>'); // hide bigPic
    $('#cf,#fsz,#curZoom,#wh,#vb').empty(); //hide file info in statusbar
    $(".cmd-toggle-zoomnpan.selected-checkbox").removeClass("selected-checkbox");
    OSV.gal.find('.selected').removeClass('selected');
    $('.cmd-delFile, .cmd-fixCurFile').addClass('disabled');
    OSV.currentFile.file = null;
    OSV.currentFile.ZoomNPan = null;

};
	
/**
*	Selects a picture
*
**/

function selectFile(evt){
	evt.stopPropagation();
	evt.preventDefault();
//    OSV.resetCurFile()
	$('.cmd-delFile, .cmd-fixCurFile').removeClass('disabled');
    $(".cmd-toggle-zoomnpan.selected-checkbox").removeClass("selected-checkbox");
	var $figure = $(evt.target).closest('.thumb');// e = <a>
    // do nothing if the pic is already selected
/*    if ($figure.hasClass('selected')) {
		return;
	}*/
	
	scrollIntoView( $figure );
	embedCopy(evt);
	OSV.currentFile.file = OSV.allpics.filter(function(file) {
		return file.path == $figure.attr('data-fileurl')
	})[0];
	setWidgetTitle(OSV.currentFile.file.nativePath)
}

/**
*	Scrolls a thumb into view 
**/

function scrollIntoView($element) {
	var $container = $element.closest('.innerScroller');
	
	var containerTop = $container.scrollTop(); 
	var containerBottom = containerTop + $container.height(); 
	var elemTop = $element[0].offsetTop - 5; // border + margin
	var elemBottom = elemTop + $element.height() + 15; // ?? xz
	
	if (elemTop < containerTop) {
		$container.scrollTop(elemTop);
	}
	else if (elemBottom > containerBottom) {
		$container.scrollTop(elemBottom - $container.height());
	}
}

/**
 *  Embeds big picture when clicking thumbnail as file copy
 *
 * @param e object <a> element of the <figure> with thumbnail
 */
function embedCopy(e){
	var $figure = $(e.target).closest('figure');// e = <a>
    // do nothing if the pic is already selected
    if ($figure.hasClass('selected')) return;
    $('#bigPic').addClass('loading').html('');
	
	var SVGRoot;
    var url = $figure.attr('data-fileurl');
    var flnm = $figure.attr('data-filename');
	var picURI = '';
	// setStatus(flnm);
	
	// if it's a raster image insert it into an SVG
	if (!isSVG(url)) {
		var vpW = $('#bigPic').width();
		var vpH = $('#bigPic').height();
		
		var img = new Image();
		img.src = url;
		
		var vbW  = img.width;
		var vbH  = img.height;
		var imgX = 0;
		var imgY = 0;
		
		// if the raster image is smaller than the viewport
		// make the viewBox same size as the viewport and center the image
		if ((img.width < vpW) && (img.height < vpH)){
			vbW = vpW;
			vbH = vpH;
			imgX = parseInt(vpW/2) - parseInt(img.width/2);
			imgY = parseInt(vpH/2) - parseInt(img.height/2);
		}
		picURI = 'data:image/svg+xml;base64,' + btoa('<?xml version="1.0" encoding="utf-8"?> \
		<svg viewBox="0 0 '+ vbW +' '+ vbH +'" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> \
			<style type="text/css">svg{-apple-dashboard-region:dashboard-region(control rectangle)}</style> \
			<image  x="'+ imgX +'" \
					y="'+ imgY +'" \
					width="'+ img.width +'" \
					height="'+ img.height +'" \
					xlink:href="'+ encodeURI(decodeURI(url)) +'" \
					/> \
		</svg>');
	}

	// if it's SVG
	else {
		var cache = OSV.OFS.mountSystemDirectory('application').resolve('cache');
		var fl = OSV.currentMP.resolve(url).copyTo(cache +'/tmp.svg', true); // TODO ACHTUNG
		picURI = '/cache/tmp.svg?'+ encodeURIComponent(flnm);
	}
	var imgObject = $('<object data="'+ picURI + '" onload="OSV.initObject(this)" onerror="handleBigPicError(this)">oops!</object>');
	$('#bigPic').html(imgObject);

    // Show some info now, 'cause onload may not fire
    $figure.addClass('selected').siblings().removeClass('selected');
    var filename = decodeURI($figure.attr('data-filename'));
    setStatus(filename, 'cf'); // Show filename in status bar
    setStatus($figure.attr('data-filesize'), 'fsz');
	
}



OSV.zoomCallback = function(oZoomNPan) {
    OSV.showCurZoom(oZoomNPan);
};

OSV.initObject = function (el){
	var	SVGRoot = el.contentDocument.documentElement;
	if (SVGRoot){
		// pass keyboard events from the <object> to the main document
		$(document.querySelector("#bigPic object").contentWindow).bind('keyup keydown keypress', function(evt) {
			$(document).trigger(evt);
		});

		var css = document.createProcessingInstruction('xml-stylesheet', 'href="../css/svg.css" type="text/css" ');
		el.contentDocument.insertBefore(css, SVGRoot);
		OSV.currentFile.ZoomNPan = new ZoomNPan(SVGRoot, {
			'zoomCallback' : OSV.zoomCallback,
			'preZoomCallback': OSV.preZoomCallback,
			'fitViewport': pref('fitViewport') === 'true',
			'fitBig': pref('fitBig') === 'true'
		});
	}
	// Remove class a bit later 'cause it may take time to render the full-sized image
	// The image is visibility:hidden when .loading
	$('#bigPic').removeClass('loading');

	// If there's <title>, make it the widget title
	var ttl = el.contentDocument.querySelector(':root>title');
	if (ttl)  setWidgetTitle(ttl.textContent);

	// Show WH, viewBox
	var w = OSV.currentFile.ZoomNPan.origWidth || '&minus;';
	var h = OSV.currentFile.ZoomNPan.origHeight || '&minus;';
	var vb = OSV.currentFile.ZoomNPan.origViewBox || '&minus;';
	setStatus( w+'/'+ h, 'wh');
	setStatus( vb, 'vb');
};

//
OSV.showCurZoom = function (oZoomNPan){
    var z   = oZoomNPan || OSV.currentFile.ZoomNPan;
    if (!z) return;
    var w   = z.origWidthPx;
    var h   = z.origHeightPx;
    var vpw = z.zoomElt.clientWidth;
    var vph = z.zoomElt.clientHeight;
    setStatus(vpw +"/"+ vph);
    var fv  = pref('fitViewport') === 'true';
    var fb  = pref('fitBig') === 'true';
    var zm  = z.zoomElt.currentScale;
    //setStatus(d([w,h,vpw,vph,fv,fb,zm]));
    if (fv || fb && (w > vpw || h > vph)) { zm = Math.min(vpw/w, vph/h) * zm }
    zm = Math.round(zm * 100);
    setStatus(zm +'%', 'curZoom');
    return zm
};

OSV.preZoomCallback = function() {
	//this = ZoomNPan Object 
	if(pref('wireframeOn') === 'true') this.wireframeMode(true)
};

/**
 *  Creates HTML output of images
 */
 
function makePicHTML(file){
    var p = file.path;
    var pic = '';
    file.html = '';
	//setStatus ("As img: " + OSV.SVGAsImg || isSVG(p) && file.isSVGZ);
	
	//  Since first alphas of 11.10 Opera can show SVG(Z) as <img> in widgets
	//  Check if Opera is >=11.10 or the file is SVGZ. Otherwise SVGZ as <object> 
	//  makes the widget almost irresponsible in v. <= 11.01
    if (OSV.SVGAsImg || isSVG(p)) {
        pic = '<img src="'+ p +'" alt="' + decodeURI(file.name) + '" class="thumb-img" onError="handleThumbError(this)"/>';
    }
    else {
        pic = '<object type="image/svg+xml" data="' + p + '" class="thumb-img" onError="handleThumbError(this)"></object>';
	}
	//d(file.nativePath.replace(/\\/g, '/'), file.nativePath)
    file.html = '<figure \
					class = "thumb" \
					data-fileurl  = "'+ p + '" \
					data-filename = "'+ file.name +'" \
					data-filesize = "'+ sizeFormat(file.fileSize) +'" \
				 > \
						<div class="thumb_wrap">'+ pic +'</div> \
						<figcaption class="thumb-caption"> \
							<a href ="file://'+ file.nativePath.replace(/\\/g, '/') +'" \
							   title="'+ decodeURI(file.name) +', '+ sizeFormat(file.fileSize) +'" >'
							    + decodeURI(file.name) +
							'</a> \
						</figcaption> \
						<a class="clicker"></a> \
				</figure>';
				
    return file.html;
}

/**
*   Error handling of thumbnails load
*/

function handleThumbError (el){
	var errMsg = "ERROR CREATING THUMBNAIL";
	$(el).hide().parent().addClass('not_loaded')
	.parent().find('.thumb-caption a')
	.attr('title', function(){
         if(pref('thumbSize') === '0') return;
		 if (this.title.indexOf(errMsg) == -1 ){
			 return this.title + ". " + errMsg;
		}
	});
	
}

/**
*   Error handling of loading the zooming picture
*/
function handleBigPicError (el){
	$('#bigPic').removeClass('loading').addClass('bigPicError');
}


/**
 *  Fixes files without xml prolog and viewBox attribute
 *  @param file File object
 *  @param log boolean If true the function will log results 
 *    - refresh thumb boolean 
 *
 */
function fixFile(file, log){
	file = file || OSV.currentFile.file;
	if (!file){
		notify ('Please select a file');
		return
	}
    if (file.isDirectory || file.isHidden || !isSVG(file)) {
		if (!log) {
			d(decodeURI(file.name) + ' is not an SVG file');
			notify (decodeURI(file.name) + ' is not an SVG file');
			setStatus (decodeURI(file.name) + ' is not an SVG file');
			return
		}
    }
    else {
		var streamedFile = readFile(file.path);
		if (!streamedFile && !log){
			notify ("Can't read file " + file.nativePath);
			setStatus ("Can't read file " + file.nativePath);
		}
		else if (stringIsSVGZ(streamedFile) && !log){
			// If this is SVGZ, skip it. Cannot rely on file extension.
			notify("Can't fix SVGZ files");
			setStatus ("Can't fix SVGZ files");
		}
		else {
			var fixedFile = sanitizeSVG(streamedFile, {fileObj: file });
			if (fixedFile.report.reportText) {
				streamedFile = fixedFile.SVGString;
				// if saved successfully
				var saved = saveFile(streamedFile, file);
				
				if (saved){
					if (!log) {	
						refreshFile(file); 
						notify(fixedFile.report.reportText)
					}
					return fixedFile.report
				}
			}
			else if (!log) {
				d(fixedFile.report,'!log');
				notify('Nothing to fix in "'+ decodeURIComponent(file.name) +'"')
			}
		}
    }
}


OSV.toggleFit = function(){
    if (!OSV.currentFile.ZoomNPan) return
    var ocz = OSV.currentFile.ZoomNPan;
    if (ocz.origWidth)   ocz.zoomElt.setAttributeNS(null,'width', ocz.origWidth);
    if (ocz.origHeight)  ocz.zoomElt.setAttributeNS(null,'height', ocz.origHeight);
    if (ocz.origViewBox){ocz.zoomElt.setAttributeNS(null,'viewBox', ocz.origViewBox)}
    else {ocz.zoomElt.removeAttributeNS(null,'viewBox')}
    //setStatus(d(ocz.origWidth,'ocz.origWidth'));
    ocz.zoom1x();
    ocz.makeViewBox(pref('fitViewport') === 'true', pref('fitBig') === 'true');
    //OSV.showCurZoom(ocz);
};
/*
 *  Process and fix all files in a folder
 *
 **/

function fixFiles(dir){
	dir = dir || OSV.currentMP;
	OSV.fixedFiles.length = 0;
	dir.refresh();
	var res = [];
	for (var i = 0, file; file = dir[i]; i++) {
		var report = fixFile(file, true);
		if ( report ) {
			res.push(report)
		}
	}
    // TODO modal report
	d(res,"fixFilesReport",3);
	OSV.scanFolder(dir);
	notify(res.length + " files were fixed.")
}


function sanitizeSVG (SVGString, opts) {
	var options = {
		addProlog: true,
		addXMLNS: true,
		removeWH: false,
		alwaysAddViewBox: false,
		addXLinkNS: false
	};
	$.extend(options, opts);
	var report = {
		fileObj: options.fileObj,
		addedProlog: false,
		addedSVGNS: false,
		addedXMLNS: false,
		addedXLinkNS: false,
		addedViewBox: false,
		removedWH: false,
		reportText: ''
	};
    var tmpSVGDOM = (new DOMParser()).parseFromString(SVGString, 'image/svg+xml');
    var SVGRoot   = tmpSVGDOM.documentElement;

	// If the file had no xmlns attribute add it and reparse as DOM again
	if (SVGRoot  == '[object Element]' && SVGRoot.nodeName == 'svg') {
		SVGString = SVGString.replace(/<svg\s/, '<svg xmlns="'+ OSV.SVGNS +'" ');
		tmpSVGDOM = (new DOMParser()).parseFromString(SVGString, 'image/svg+xml');
    	SVGRoot   = tmpSVGDOM.documentElement;
		report.addedSVGNS = true;
	}
    if  (SVGRoot == '[object SVGSVGElement]') {
		if (SVGString.substring(0,9).indexOf('<?xml ') == -1 && options.addProlog) {
			// opera will add prolog when serializing
			report.addedProlog = true;
		}
		if (options.addXLinkNS) {
			SVGRoot.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink');
			report.addedXLinkNS = true;
		}
		var wAttr = SVGRoot.getAttributeNS(null, "width");
		var hAttr = SVGRoot.getAttributeNS(null, "height");
		var vB    = SVGRoot.viewBox.baseVal; //SVGRoot.getAttributeNS(null, "viewBox");

        // If there are NO width & height & viewbox OR @width or @height are percentages, try to guess them
		if ((!wAttr && !hAttr && !(vB && vB.width)) || ((wAttr || hAttr) && (wAttr.indexOf('%') != -1 || hAttr.indexOf('%') != -1 ))) {
			var BBox  = SVGRoot.getBBox();
			vB.x      = BBox.x;
			vB.y      = BBox.y;
			vB.width  = BBox.width;
			vB.height = BBox.height;
			report.addedViewBox = true
		}
/*		else if ((wAttr || hAttr) && !vB.width && options.alwaysAddViewBox) {
		// If there IS width or height and NO viewBox,
		// generate viewbox based on them
			vB.x      = 0;//SVGRoot.x.baseVal.value;
			vB.y      = 0;//SVGRoot.y.baseVal.value;
			vB.width  = SVGRoot.width.baseVal.value || w;
			vB.height = SVGRoot.height.baseVal.value || h;

			SVGRoot.removeAttributeNS(null, 'width');
			SVGRoot.removeAttributeNS(null, 'height');

			report += '';
		}
		else if((wAttr || hAttr) && vB.width && options.removeWH){
			// If there are ALL OF width/height/viewBox
			// only remove width and height attibutes
			// or image won't scale to fit
			SVGRoot.removeAttributeNS(null, 'width');
			SVGRoot.removeAttributeNS(null, 'height');
		}*/

		for (var prop in report) {
			if (report[prop] === true) {
				if ( prop == 'addedProlog')  { report.reportText += 'XML prolog added. \r\n'}
				if ( prop == 'addedSVGNS')   { report.reportText += 'xmlns attribute added. \r\n'}
				if ( prop == 'addedXLinkNS') { report.reportText += 'XLink namespace added. \r\n'}
				if ( prop == 'addedViewBox') { report.reportText += 'The file had no width, heigth, and viewBox attributes. ViewBox created. \r\n'}
			}
		}
		if (report.reportText){
			tmpSVGDOM.insertBefore(tmpSVGDOM.createTextNode('\r\n'), SVGRoot);
			tmpSVGDOM.insertBefore(tmpSVGDOM.createComment ('\r\n'+ report.reportText), SVGRoot);
			tmpSVGDOM.insertBefore(tmpSVGDOM.createTextNode('\r\n'), SVGRoot);
		}
		SVGString = (new XMLSerializer()).serializeToString(tmpSVGDOM);
	}
	return {'SVGString': SVGString, 'report': report}
}

function refreshFile (file){
	//setStatus('refreshfile run')
	file = file || OSV.currentFile.file;
	var $img = $('.thumb img[src="'+file.path+'"]').clone(true);
	$img.attr('src', function (e) {return this.src + '#'+ Math.random() +'?'+ Math.random()});
	$('.thumb img[src="'+file.path+'"]').replaceWith($img);
	// remove the image and insert it again with search string in url
	$('.thumb[data-filename="'+ file.name +'"]').removeClass('selected').click();

	return {thumbsrc: $('.thumb[data-filename="'+ file.name +'"] .thumb-img').attr('src'), obj: $('#bigPic object').attr('data')}

}

/**
 * Helper function to read a file.
 *
 * @param   {String}    path    The path to the file.
 *
 * @private
 */
function readFile( path , length){
	try {
		file = OSV.currentMP.resolve( path );
	}
	catch ( ex ){
		throw "Error accessing the filesystem: " + ex;
	}
	if( file.exists ){
		try{
			var stream = file.open( file, opera.io.filemode.READ );
			var	bytes = length || stream.bytesAvailable;
			return stream.read( bytes, 'UTF-8' );
		}
		catch( ex ){
			throw 'Error reading file "' + path + '": ' + ex;
		}
	}
	return null;
}

function saveFile (fileContents, file) {
	var options = {
		backup: true
	};
	try {
		if (options.backup) {
			//var fl = OSV.OFS.mountPoints[0].resolve(url).copyTo(cache +'/tmp.svg', true); // ACHTUNG
			if (!file.copyTo(file.path+'.bak')) {
				throw new Error('Couldn\'t create backup before saving')
			}
		}
		var stream = file.open( null , opera.io.filemode.WRITE);
		stream.write(fileContents);
		stream.close();
		return true
	}
	catch (e) {
		opera.postError("Saving file " +file.name +" failed: "+ e);
		notify("Saving file " +file.name +" failed");
		setStatus ("Saving file " +file.name +" failed");
	}
}

function deleteFile (file) {
	if(!file) {
		d('Nothing to delete');
		return
	}
	try {
		// todo update numbers in pager
		// remove bigpic
		//	OSV.currentMP.resolve(decodeURI(file.name)).copyTo(file.name+'.bak')
		var deleted = OSV.currentMP.deleteFile(file);
		if (deleted) {
			d(deleted, 'file.deleteFile(file)');
			OSV.allpics = jQuery.grep(OSV.allpics, function(fileObj) {
				return fileObj.name != file.name;
			});
			OSV.currentFile.file = null;
			OSV.currentFile.ZoomNPan = null;
			$('#bigPic').html('');

			$('.thumb[data-filename="'+ file.name+'"]').remove();
			notify("File " +decodeURI(file.name) +" was deleted.");
			setStatus ("File " +decodeURI(file.name) +" was deleted.");
			}

	}
	catch (e) {
		opera.postError("Deleting file " +file.name +" failed: "+ e);
		notify("Deleting file " +file.name +" failed");
		setStatus ("Deleting file " +file.name +" failed");
	}
}

function copyFile(path, overwrite, callback){

}

 OSV.setThumbsSize = function(size) {
	if (!size){ size = '0'}
	$('.setThumbs').removeClass('selected-radio');
	$('.setThumbs[data-size = "'+ size +'"]').addClass('selected-radio');

	var newSize = 'thumbs_'+ size;
	setPref(size, 'thumbSize');
	$('#thumbsPane').removeClass (function (index, classnm) {
		var matches = classnm.match (/thumbs_\d+/g) || [];
		return (matches.join (' '));
	}).addClass(newSize);

};

OSV.toggleTransparencyGrid = function ( turnOn ){
	var $togglr = $('.cmd-toggle-grid');
	var $grid   = $('#singlePic');

	turnOn = arguments[0] && (arguments[0] == true);

	if (pref('trGrid') === 'true' && !turnOn){
		setPref('false', 'trGrid');
		$('.cmd-toggle-grid.menuitem-checkbox').removeClass('selected-checkbox');
		$grid.removeClass('checkerboard');
	}
	else {
		setPref('true', 'trGrid');
		$togglr.addClass('selected-checkbox');
		$grid.addClass('checkerboard');
	}
};
OSV.toggleFitViewport = function(turnOn){
    $(".cmd-fit-viewport.menuitem-checkbox").toggleClass("selected-checkbox");
    var turnVal = (turnOn || pref('fitViewport') !== 'true') || 'false';
    setPref(turnVal,'fitViewport');
    OSV.toggleFit();
};
OSV.toggleFitBig = function(turnOn){
    $(".cmd-fit-big.menuitem-checkbox").toggleClass("selected-checkbox");
    var turnVal = (turnOn || pref('fitBig') !== 'true') || 'false';
    setPref(turnVal,'fitBig');
    OSV.toggleFit();
};

OSV.toggleWireframeMode = function(turnOn){
	if (pref('wireframeOn') === 'true' && !arguments[0]){
		setPref('false', 'wireframeOn');
		$('.cmd-toggle-wireframe.menuitem-checkbox').removeClass('selected-checkbox');
	}
	else {
		setPref('true', 'wireframeOn');
		$('.cmd-toggle-wireframe.menuitem-checkbox').addClass('selected-checkbox');
	}
	if (OSV.currentFile.ZoomNPan) OSV.currentFile.ZoomNPan.wireframeMode(pref('wireframeOn') === 'true');
};

OSV.toggleShowBitmap = function(turnOn){
/*    notify('!')*/
    setStatus(d(arguments[0]));
    if(pref('includeBitmap') === 'true' && !arguments[0]){
        setPref('false', 'includeBitmap');
		$('.cmd-show-bitmap.menuitem-checkbox').removeClass('selected-checkbox');
    }
    else{
        setPref('true', 'includeBitmap');
		$('.cmd-show-bitmap.menuitem-checkbox').addClass('selected-checkbox');
    }
    if(OSV.currentMP){
        OSV.scanFolder(OSV.currentMP)
    }
}

OSV.zoomIn = function() {
	if (OSV.currentFile.ZoomNPan) OSV.currentFile.ZoomNPan.zoomIn();
};

OSV.zoomOut = function() {
	if (OSV.currentFile.ZoomNPan) OSV.currentFile.ZoomNPan.zoomOut();
};

OSV.zoom1x = function() {
	if (OSV.currentFile.ZoomNPan) OSV.currentFile.ZoomNPan.animateZoom1x();
};
OSV.toggleZoomNPan = function () {
	if (!OSV.currentFile.ZoomNPan) return;
    OSV.currentFile.ZoomNPan.toggleZoomNPan();
    $(".cmd-toggle-zoomnpan.menuitem-checkbox").toggleClass("selected-checkbox")
};

OSV.focusNextThumb = function(evt){
	var $focused = $('.thumb.selected');
	if (!$focused.length){
		$('.thumb:first-child').click()
	}
	else if ($focused.is(':last-child')){
		if($('#pager .next.current').length){ return }
		else {
			$('#pager .next').click();
			$('.thumb:first-child').click()
		}
	}
	else {
		$focused.next().click();
	}
};

OSV.focusPrevThumb = function(evt){
	var $focused = $('.thumb.selected');
	if (!$focused.length){
		$('.thumb:last-child').click()
	}
	else if ($focused.is(':first-child')){		
		//if this is the first page
		if($('#pager .prev.current').length){ return }
		else {
			$('#pager .prev').click();
			$('.thumb:last-child').click()
		}
	}
	else {
		$focused.prev().click();
	}
};

OSV.focusDownThumb = function(evt){
	var skipCount = OSV.getSkipThumbsCount();
	var selIndex  = $('.thumb.selected').index();
	if (selIndex == -1){
		$('.thumb:first-child').click();
	}
	else if ($('.thumb').eq(selIndex + skipCount)[0]){
		$('.thumb').eq(selIndex + skipCount).click()
	}
	else if ($('.thumb.selected').is(':last-child')){
		// if it's not the last page
		if($('#pager .next.current').length) return 
		else {
			$('#pager .next').click();
			$('.thumb:first-child').click()
		}
	}
	else {
		$('.thumb:last-child').click();
	}
};

OSV.focusUpThumb = function (evt){
	var skipCount = OSV.getSkipThumbsCount();
	var selIndex  = $('.thumb.selected').index();
	if (selIndex == -1){
		$('.thumb:last-child').click();
	}
	else if ((selIndex - skipCount >= 0)){
		$('.thumb').eq(selIndex - skipCount).click();
	}
	else if ($('.thumb.selected').is(':first-child')){
		// if it's not the last page
		if($('#pager .prev.current').length) return 
		else {
			$('#pager .prev').click();
			$('.thumb:last-child').click()
		}
	}
	else {
		$('.thumb:first-child').click();
	}
};

OSV.getSkipThumbsCount = function(){
	var availWidth = $('#thumbsPane .innerScroller')[0].scrollWidth;
	var $aThumb    = $('#thumbsPane .thumb').eq(1);
	var thumbWidth = parseInt($aThumb[0].offsetWidth) + parseInt($aThumb.css('margin-left')) + parseInt($aThumb.css('margin-right'));
	return Math.floor(availWidth / thumbWidth);
};


/**
 * Checks if the file needs to be added to the
 * allpics array based on widget options
 *
 * @param string {string} string to be checked
 */
function isPicture(string){
	if (typeof string != 'string') return;

	if (pref('includeBitmap') === "false" || !pref('includeBitmap')) {
		return string.match(/\.svgz?$/i);
	}
	else {
		return string.match(/(\.jpe?g$)|(\.a?png$)|(\.gif$)|(\.svgz?$)|(\.ico$)|(\.bmp$)|(\.tiff?$)|(\.webp$)/i)
	}
}

function isRaster(string){
        var raster = /(\.jpe?g$)|(\.a?png$)|(\.gif$)|(\.ico$)|(\.bmp$)|(\.tiff?$)|(\.webp$)/i;
		
		if (string.match(raster)) return true
}

/**
 *  Checks if the file is SVG(z)
 *  @input <object> file or string
 */
function isSVG(file){
	var path = file;
	if (typeof file == 'string') { path = file }
	else if (file.path)          { path = file.path }
    // We don't filter out SVGZ because SVGZ can actually be SVG with wrong extension
    if (path.match(/\.svgz?$/i)) {
        return true;
    }
}

/**
 *
 * @param file File object
 */
 
function isSVGZ(file){
	if (!file || !isSVG(file)){
        file.isSVGZ = false;
		return file
	}
	var streamedFile = readFile(file.path, 2);//file.readContent(2);
	file.isSVGZ = stringIsSVGZ(streamedFile);
	return file;
}

function stringIsSVGZ (string) {
	return !!string.match(/^\037/);
}

function createButton(id,action,title,imgName){
	var label = $('<label class="button">');
	var btn = $('<button class="zoom"/>');
	btn.attr({
		'id': id,
		'title': title
	
	})
	.append('<img src="../img/'+ imgName +'" alt="'+ title +'" />')
	.mouseup(action);
	
	label.append(btn);
	$('#dynButtons').append(label);
	
}

function toggleAnimation(elt){
	return
	if(!elt){
		elt = $('#bigPic svg');
	}
//TODO pausing
}

/**
 * @params {}
 * 	 msg 
 *   OKText
 *   cancelText
 *   callback 
 *   cancelCallback
 *   events 
 **/
function modalConfirm(params) {
	var options = {
		msg:'Are you sure?',
		OKText: 'OK',
		cancelText: 'Cancel',
		callback: function (){},
		cancelCallback: $.modal.close,
		events: function(){},
		silentID: ''
	};
	$.extend(options, params);
	if (!params ) return;
	
	if(options.silentID && pref(options.silentID) == 'true') {
		options.callback();
		return
	}
	var html = '\
    <div class="modal-content confirmation">\
	 <div class="modal-header">'+ widget.name+'</div>\
	 <div class="modal-text-wrapper">\
	  <div class="modal-icon"/>\
	  <div class="modal-text">\
	  	<div class="modal-inner-wrap">\
	  	 '+ options.msg +
	     '<div class="modal-more">\
	       <label><input type="checkbox" id="'+ options.silentID +'" onchange="setPref(this.checked.toString(), \''+ options.silentID +'\')"/> Dont ask again </label>\
	      </div>\
	    </div>\
	 </div>\
	 </div>\
	 <div class="modal-buttons">\
	  <button class="" id="btn-confirmation-ok">'+ options.OKText+'</button>\
	  <button id="btn-confirmation-cancel">'+ options.cancelText+'</button>\
	 </div>\
	</div>\
	';
	$.modal(html, {onShow: function(dialog){
		$('#btn-confirmation-cancel', dialog.data).click(function(e){options.cancelCallback(); return false});
		$('#btn-confirmation-ok', dialog.data).click(function(e){
			$.modal.close();
			options.callback();
			return false
		}).focus();
		if (options.events){
			// ?%)
			options.events();//.apply(this, arguments)
		}
	}})
	
}

OSV.widgetInfo = function(){
	var info = '';
	info += '<article id="aboutWidget">';
	info += '<h1>'+ widget.name +'</h1>';
	info += '<p><strong>Version:</strong> '+ widget.version +'</p>';
	info += '<p><strong>Author:</strong> <a href="'+ widget.authorHref+'">'+ widget.author+'</a></p>';
	info += '<p><strong>Environment:</strong> '+ navigator.userAgent +'</p>';
	info += '<p><a href="'+ OSV.widgetAddr+'">Widget page</a> / <a href="http://my.opera.com/SpShut/blog/opera-svg-viewer-official-page">Support page</a> / <a href="http://code.google.com/p/opera-svg-viewer/">Source code</a></p>';
	info += '<p><p>Try my <a href="https://addons.opera.com/addons/extensions/details/svg-zoomnpan/">SVG ZoomNPan Opera extension</a> to zoom individual SVGs.</p>';
	info += '</article>';
	return info
}


/**
 * Sets title of the widget
 * @param {String} title
 */
function setWidgetTitle(title){
    //Cleaup any HTML from the tile.
    var defTitle = widget.name;
    if (title) {
        title = decodeURI(title);
        title = '[' + title.replace(/<\/?[a-z][a-z0-9]*[^<>]*>/g, "") + '] \u2014 ' + defTitle;
        document.title = title;
    }
    else {
        document.title = defTitle;
    }
}


window.toid = function(uri){
    uri = uri || '';
    return uri.replace(/%/g,'_PRCNT_')
}
window.fromid = function(uri){
    uri = uri || '';
    return uri.replace(/_PRCNT_/g,'%')
}

/*
 *  Short wrapper for widget.preferenceForKey
 */
function pref(key){
    return widget.preferenceForKey(key);
}

/*
 *  Short wrapper for widget.setPreferenceForKey
 */
function setPref(val, key){
    widget.setPreferenceForKey(val, key);
}


// From http://snipplr.com/view/5949/format-humanize-file-byte-size-presentation-in-javascript/
function sizeFormat(filesize){
    if (filesize >= 1073741824) {
        filesize = number_format(filesize / 1073741824, 2, '.', '') + ' Gb';
    }
    else {
        if (filesize >= 1048576) {
            filesize = number_format(filesize / 1048576, 2, '.', '') + ' Mb';
        }
        else {
            if (filesize >= 1024) {
                filesize = number_format(filesize / 1024, 0) + ' Kb';
            }
            else {
                filesize = number_format(filesize, 0) + ' bytes';
            }
        }
    }
    return filesize;
}
/**
*	Dumps all mountpoints to console
*/
function dumpMPs(){
	d(OSV.OFS.mountPoints.length, 'OSV.OFS.mountPoints.length', 2);
	for ( var i=OSV.OFS.mountPoints.length -1; i>=0; i--) {
		d(OSV.OFS.mountPoints[i], 'OSV.OFS.mountPoints['+ i +']');
	}
}


//})()
